using System;
using System.ComponentModel;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Drawing2D;

namespace Felbot.Interface {
    // Felbot.Interface.MdiTabStripButton:
    //  Source:
    //   CODEPROJECT.COM ARTICLE
    //   "Easy Tabbed Mdi Interface Using the ToolStrip"
    //   By beep
    //   http://www.codeproject.com/KB/toolbars/MdiTabToolStrip.aspx
    //
    //  Modifications:
    //   Ribose (nmBook):
    //    Cleaned up excessiveness, added hover colors,
    //    removed close button colors (made same as text colors),
    //    added nice border and drag and drop

    /// <summary>
    /// A special button for MdiTabStrip. This button has an associated Form
    /// object that is hooked in to its events. This class overrides the OnPaint
    /// event to replace the drop-down portion of the button with a close box.
    /// </summary>
    public class MdiTabStripButton : ToolStripSplitButton {
        #region State
        private Form m_MdiChild;
        private bool m_Hover = false;
        #endregion //--State

        #region Construction
        /// <summary>
        /// Constructs a new MdiTabStripButton with the given form.
        /// </summary>
        /// <param name="mdiChild"></param>
        public MdiTabStripButton(Form mdiChild) {
            if (null == mdiChild)
                throw new ArgumentNullException("mdiChild");

            InitializeComponent();
            SetMdiChild(mdiChild);
        }

        #region Designer
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary> 
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing) {
            if (disposing && (components != null)) {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Component Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent() {
            components = new System.ComponentModel.Container();
        }
        #endregion
        #endregion
        #endregion //--Construction

        #region Private and Protected Members
        /// <summary>
        /// Sets the form associated with this MdiTabStripButton.
        /// </summary>
        /// <param name="f"></param>
        private void SetMdiChild(Form f) {
            if (null == f)
                return;

            if (null != m_MdiChild) {
                m_MdiChild.Activated -= new EventHandler(FormActivated);
                m_MdiChild.HandleDestroyed -= new EventHandler(FormHandleDestroyed);
                m_MdiChild.TextChanged -= new EventHandler(FormTextChanged);
            }

            m_MdiChild = f;

            f.WindowState = FormWindowState.Maximized;
            f.MaximizeBox = false;
            f.MinimizeBox = false;
            f.Activated += new EventHandler(FormActivated);
            f.HandleDestroyed += new EventHandler(FormHandleDestroyed);
            f.TextChanged += new EventHandler(FormTextChanged);
        }

        /// <summary>
        /// Event handler called when form activated.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FormActivated(object sender, EventArgs e) {
            MdiTabStrip ts = Owner as MdiTabStrip;
            if (null != ts)
                ts.SelectedTab = this;
            Form f = sender as Form;
            if (null != f)
                f.WindowState = FormWindowState.Maximized;
        }

        /// <summary>
        /// Event handler called when form text changes.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FormTextChanged(object sender, EventArgs e) {
            Form f = sender as Form;
            if (f.Text.Length > 25)
                Text = f.Text.Substring(0, 22) + "...";
            else
                Text = f.Text;
            ToolTipText = f.Text;
        }

        /// <summary>
        /// Event handler called when the form is destroyed. At this point,
        /// this button will remove itself from its Owner tab strip.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FormHandleDestroyed(object sender, EventArgs e) {
            Form f = sender as Form;
            f.Activated -= new EventHandler(FormActivated);
            f.TextChanged -= new EventHandler(FormTextChanged);
            f.HandleDestroyed -= new EventHandler(FormHandleDestroyed);
            Owner.Items.Remove(this);
        }
        #endregion //--Private and Protected Members

        #region Overrides
        /// <summary>
        /// Overridden. Puts some space between tab buttons.
        /// </summary>
        protected override Padding DefaultMargin {
            get { return new Padding(1, 1, 5, 5); }
        }

        /// <summary>
        /// Overridden. Paints over the drop-down with an x.
        /// </summary>
        /// <param name="e"></param>
        protected override void OnPaint(PaintEventArgs e) {
            base.OnPaint(e);
            Graphics g = e.Graphics;

            this.ToolTipText = this.Text;
            if (this.Text.Length > 33)
                this.Text = this.Text.Substring(0, 30) + "...";
            this.Width = 100;
            this.Height = 25;

            //get colors
            Color back, fore, border, close, shadow, highlight;
            shadow = SystemColors.ControlDarkDark;
            highlight = SystemColors.ControlLightLight;
            switch (ActiveState) {
                case MdiTabStripButtonState.Active:
                    back = ActiveBackColor;
                    fore = ActiveForeColor;
                    border = ActiveBorderColor;
                    close = ActiveForeColor;
                    break;
                case MdiTabStripButtonState.ActiveHover:
                case MdiTabStripButtonState.Hover:
                    back = HoverBackColor;
                    fore = HoverForeColor;
                    border = HoverBorderColor;
                    close = HoverForeColor;
                    break;
                default:
                case MdiTabStripButtonState.Inactive:
                    back = InactiveBackColor;
                    fore = InactiveForeColor;
                    border = InactiveBorderColor;
                    close = InactiveForeColor;
                    break;
            }

            //draw tab background
            Rectangle bounds = this.Bounds;// e.ClipRectangle;
            Rectangle btnbounds = this.ButtonBounds;
            Rectangle closebounds = this.DropDownButtonBounds;
            using (Pen backp = new Pen(back, 1.0F))
            using (Pen forep = new Pen(fore, 1.0F))
            using (GraphicsPath gp = new GraphicsPath(FillMode.Alternate)) {
                gp.AddCurve(new Point[] {
                    new Point(bounds.Left + 2, bounds.Bottom - 4),
                    new Point(bounds.Left + 2, bounds.Top - 2),
                    new Point(bounds.Left + 4, bounds.Top),
                    new Point(bounds.Right - 4, bounds.Top),
                    new Point(bounds.Right - 2, bounds.Top - 2),
                    new Point(bounds.Right, bounds.Bottom - 4)
                }, 0, 2, 0.1F);
                using (LinearGradientBrush backb =
                    new LinearGradientBrush(
                        new RectangleF(
                            bounds.Left, bounds.Top,
                            bounds.Width, bounds.Top + 4),
                        highlight, back,
                        270.0F))
                    g.FillPath(backb, gp);
                using (LinearGradientBrush backb =
                    new LinearGradientBrush(
                        new RectangleF(
                            bounds.Left, bounds.Bottom - 4,
                            bounds.Width, bounds.Bottom),
                        back, shadow,
                        270.0F))
                    g.FillPath(backb, gp);
                g.DrawPath(forep, gp);
            }
            
            //draw text
            using (Pen forep = new Pen(fore, 1.0F)) {
                g.DrawString(
                    this.Text,
                    this.Font,
                    forep.Brush,
                    new RectangleF(
                        btnbounds.Left + 5,
                        btnbounds.Top + 2,
                        btnbounds.Width - 10,
                        btnbounds.Height - 4));
            }

            //draw close
            using (Pen shadowp = new Pen(shadow, 2.0F))
            using (Pen xp = new Pen(fore, 2.0F)) {
                g.DrawLine(shadowp,
                    closebounds.Left + 1, closebounds.Top + 1,
                    closebounds.Right + 1, closebounds.Bottom + 1);
                g.DrawLine(shadowp,
                    closebounds.Left + 1, closebounds.Bottom + 1, 
                    closebounds.Right + 1, closebounds.Top + 1);
                g.DrawLine(xp,
                    closebounds.Left, closebounds.Top,
                    closebounds.Right, closebounds.Bottom);
                g.DrawLine(xp,
                    closebounds.Left, closebounds.Bottom,
                    closebounds.Right, closebounds.Top);
            }
            
            //draw bottom
            using (Pen bottomlinep = new Pen(ActiveBackColor, 3.0F))
            using (Pen bottomborderp = new Pen(border, 1.0F))
            using (Pen bottomfadep = new Pen((ActiveState == MdiTabStripButtonState.Active || ActiveState == MdiTabStripButtonState.ActiveHover ? back : border), 1.0F)) {
                g.DrawLine(bottomlinep,
                    bounds.Left, bounds.Bottom - 2,
                    bounds.Right, bounds.Bottom - 2);
                g.DrawLine(bottomborderp,
                    bounds.Left, bounds.Bottom - 4,
                    bounds.Left + 2, bounds.Bottom - 4);
                g.DrawLine(bottomborderp,
                    bounds.Left, bounds.Bottom,
                    bounds.Right, bounds.Bottom);
                g.DrawLine(bottomfadep,
                    bounds.Left + 2, bounds.Bottom - 4,
                    bounds.Right, bounds.Bottom - 4);
            }
        }

        /// <summary>
        /// Overridden. Activates its Form.
        /// </summary>
        /// <param name="e"></param>
        protected override void OnButtonClick(EventArgs e) {
            base.OnButtonClick(e);
            Form f = GetMdiChild();
            if (null != f) {
                f.Activate();
                f.WindowState = FormWindowState.Maximized;
            }
        }

        /// <summary>
        /// Overridden. Acts as a Close() for its Form.
        /// </summary>
        /// <param name="e"></param>
        protected override void OnDropDownShow(EventArgs e) {
            base.OnDropDownShow(e);
            HideDropDown();
            Form f = GetMdiChild();
            if (null != f)
                f.Close();
        }

        /// <summary>
        /// Overridden to hide ForeColor.
        /// </summary>
        [Browsable(false)]
        public override Color ForeColor {
            get {
                if (IsSelectedTab)
                    return ActiveForeColor;

                return InactiveForeColor;
            }
            set { }
        }

        /// <summary>
        /// Overridden to light up button on hover.
        /// </summary>
        protected override void OnMouseEnter(EventArgs e) {
            base.OnMouseEnter(e);
            m_Hover = true;
        }

        /// <summary>
        /// Overridden to dim down button on leave.
        /// </summary>
        protected override void OnMouseLeave(EventArgs e) {
            base.OnMouseLeave(e);
            m_Hover = false;
        }
        #endregion //--Overrides

        #region Public Interface
        /// <summary>
        /// Gets the forecolor if active.
        /// </summary>
        [Browsable(false)]
        public Color ActiveForeColor {
            get {
                MdiTabStrip ts = Owner as MdiTabStrip;
                if (null != ts)
                    return ts.ActiveForeColor;

                return SystemColors.ControlText;
            }
        }

        /// <summary>
        /// Gets the forecolor if hovered over.
        /// </summary>
        [Browsable(false)]
        public Color HoverForeColor {
            get {
                MdiTabStrip ts = Owner as MdiTabStrip;
                if (null != ts)
                    return ts.HoverForeColor;

                return SystemColors.HighlightText;
            }
        }

        /// <summary>
        /// Gets the forecolor if inactive.
        /// </summary>
        [Browsable(false)]
        public Color InactiveForeColor {
            get {
                MdiTabStrip ts = Owner as MdiTabStrip;
                if (null != ts)
                    return ts.InactiveForeColor;

                return SystemColors.GrayText;
            }
        }
        /// <summary>
        /// Gets the backcolor if active.
        /// </summary>
        [Browsable(false)]
        public Color ActiveBackColor {
            get {
                MdiTabStrip ts = Owner as MdiTabStrip;
                if (null != ts)
                    return ts.ActiveBackColor;

                return SystemColors.ControlLight;
            }
        }

        /// <summary>
        /// Gets the backcolor if hovered over.
        /// </summary>
        [Browsable(false)]
        public Color HoverBackColor {
            get {
                MdiTabStrip ts = Owner as MdiTabStrip;
                if (null != ts)
                    return ts.HoverBackColor;

                return SystemColors.Highlight;
            }
        }

        /// <summary>
        /// Gets the backcolor if inactive.
        /// </summary>
        [Browsable(false)]
        public Color InactiveBackColor {
            get {
                MdiTabStrip ts = Owner as MdiTabStrip;
                if (null != ts)
                    return ts.InactiveBackColor;

                return SystemColors.ControlDark;
            }
        }

        /// <summary>
        /// Gets the border color if active.
        /// </summary>
        [Browsable(false)]
        public Color ActiveBorderColor {
            get {
                MdiTabStrip ts = Owner as MdiTabStrip;
                if (null != ts)
                    return ts.ActiveBorderColor;

                return SystemColors.ActiveBorder;
            }
        }

        /// <summary>
        /// Gets the border color if hovered over.
        /// </summary>
        [Browsable(false)]
        public Color HoverBorderColor {
            get {
                MdiTabStrip ts = Owner as MdiTabStrip;
                if (null != ts)
                    return ts.HoverBorderColor;

                return SystemColors.InactiveBorder;
            }
        }

        /// <summary>
        /// Gets the border color if inactive.
        /// </summary>
        [Browsable(false)]
        public Color InactiveBorderColor {
            get {
                MdiTabStrip ts = Owner as MdiTabStrip;
                if (null != ts)
                    return ts.InactiveBorderColor;

                return SystemColors.InactiveBorder;
            }
        }

        /// <summary>
        /// Gets a value indicating whether to draw a border.
        /// </summary>
        [Browsable(false)]
        public bool DrawBorder {
            get {
                MdiTabStrip ts = Owner as MdiTabStrip;
                if (null != ts)
                    return ts.DrawBorder;

                return true;
            }
        }

        /// <summary>
        /// Gets whether this is the selected tab in the MdiTabStrip.
        /// </summary>
        [Browsable(false)]
        public bool IsSelectedTab {
            get {
                MdiTabStrip ts = Owner as MdiTabStrip;
                if (null == ts || !Equals(ts.SelectedTab))
                    return false;

                return true;
            }
        }

        /// <summary>
        /// Gets the active state of the tab.
        /// </summary>
        [Browsable(false)]
        public MdiTabStripButtonState ActiveState {
            get {
                if (IsSelectedTab)
                    if (m_Hover)
                        return MdiTabStripButtonState.ActiveHover;
                    else
                        return MdiTabStripButtonState.Active;
                else if (m_Hover)
                    return MdiTabStripButtonState.Hover;
                else
                    return MdiTabStripButtonState.Inactive;
            }
        }

        /// <summary>
        /// Gets the Form associated with this MdiTabStripButton.
        /// </summary>
        /// <returns></returns>
        public Form GetMdiChild() {
            return m_MdiChild;
        }
        #endregion //--Public Interface
    }

    public enum MdiTabStripButtonState {
        ActiveHover,
        Active,
        Hover,
        Inactive
    }
}

